package com.taglab.chic.mvc.spring;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.core.io.Resource;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;

/**
 * @author Markus Kobler
 */
public class RedirectHandlerMapping extends AbstractHandlerMapping {

  private final Logger logger = LoggerFactory.getLogger( this.getClass() );
  
  /**
   * PropertiesConfiguration is useful because it is reloadable. We use a FileChangedReloadingStrategy by default.
   */
  private PropertiesConfiguration redirects;

  private String redirectPropertiesPath;
  
  public RedirectHandlerMapping() {
    // defaults to first handler
    setOrder(1);
  }  
  
  @Required
  public void setRedirectPropertiesPath(String redirectPropertiesPath) {
    this.redirectPropertiesPath = redirectPropertiesPath;  
  }
  
  public void initialiseRedirects() {
    
    Resource redirectsResource = getApplicationContext().getResource( redirectPropertiesPath );
    
    if( !redirectsResource.exists() ) {
      logger.error( "Couldn't find redirects properties at file path: {}", redirectPropertiesPath );
      return;
    }
    
    try {
    
      redirects = new PropertiesConfiguration( redirectsResource.getFile() );
      redirects.setReloadingStrategy( new FileChangedReloadingStrategy() );
    
    } catch( IOException ioex ) {
      logger.error( "Error reading redirect properties file", ioex );
    } catch( ConfigurationException cex ) {
      logger.error( "Redirect configuration error", cex );
    }
    
  }

  @Override
  protected Object getHandlerInternal(HttpServletRequest request) throws Exception {

    // This can't be done when the property is first set because it won't have access to the application context.
    if( redirects == null ) initialiseRedirects();
    
    return lookupRedirect(request);
  
  }


  protected RedirectHandler lookupRedirect(HttpServletRequest request ) {

    String destination = (String)redirects.getString(request.getRequestURI());
    
    if( destination != null ) {
      logger.debug( "Found redirect '{}' for URI '{}'", destination, request.getRequestURI() );
      return new RedirectHandler(destination);
    }
    
    return null;
  }


  /**
   *
   * XXX Add support for perm redirects, codes etc
   */
  private class RedirectHandler implements HttpRequestHandler {

    private String destination;

    private RedirectHandler(String destination) {
      this.destination = destination;
    }

    public void handleRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
      response.sendRedirect(destination);
    }

  }

}